import createDOMElement from "./createDOMElement";
import mountElement from "./mountElement";
import updateNodeElement from "./updateNodeElement";
import updateTextNode from "./updateTextNode";
import unmountNode from "./unmountNode";
import diffComponent from "./diffComponent";
export default function diff(virtualDOM, container, oldDOM) {
  const oldVirtualDOM = oldDOM && oldDOM._virtualDOM;
  const oldComponent = oldVirtualDOM && oldVirtualDOM.component;

  // 判断 oldDOM 是否存在
  if (!oldDOM) {
    mountElement(virtualDOM, container);
  } else if (
    // 对比两个节点类型不同，且节点类型不是组件，因为组件类型单独处理
    virtualDOM.type !== oldVirtualDOM.type &&
    typeof virtualDOM.type !== "function"
  ) {
    const newElement = createDOMElement(virtualDOM);
    oldDOM.parentNode.replaceChild(newElement, oldDOM);
  } else if (typeof virtualDOM.type === "function") {
    // 组件类型单独处理
    /*
     ** 1. 组件本身的 virtualDOM 对象，用来获取组件最新的props
     ** 2. 要更新组件的实例对象，用来调用组件的生命周期函数，更新组件的props属性，获取到组件返回的最新的 virtualDOM
     ** 3. 要更新的 DOM 对象，在更新组件时，需要在已有 DOM 对象的身上进行修改，实现DOM最小化操作，获取旧的 virtualDOM
     ** 4. 要更新的组件和旧组件不是同一个组件，则直接将组件返回的最新的 virtualDOM 显示在页面中，此时需要父级容器 container
     */
    diffComponent(virtualDOM, oldComponent, oldDOM, container);
  } else if (oldVirtualDOM && virtualDOM.type === oldVirtualDOM.type) {
    if (virtualDOM.type == "text") {
      // 更新内容
      updateTextNode(virtualDOM, oldVirtualDOM, oldDOM);
    } else {
      // 更新元素属性
      updateNodeElement(oldDOM, virtualDOM, oldVirtualDOM);
    }

    // 1. 将拥有key属性的子元素放置在同一个单独的对象中
    let keyedElements = {};
    for (let i = 0, len = oldDOM.childNodes.length; i < len; i++) {
      let domElement = oldDOM.childNodes[i];
      // 值1表示元素节点（Element Node）
      if (domElement.nodeType === 1) {
        let key = domElement.getAttribute("key");
        if (key) {
          keyedElements[key] = domElement;
        }
      }
    }

    let hasNokey = Object.keys(keyedElements).length === 0;

    if (hasNokey) {
      // 均无key属性，直接循环子元素，对比渲染
      virtualDOM.children.forEach((child, i) => {
        diff(child, oldDOM, oldDOM.childNodes[i]);
      });
    } else {
      // 2. 循环 virtualDOM 的子元素，获取子元素的 key 属性
      virtualDOM.children.forEach((child, i) => {
        let key = child.props.key;
        if (key) {
          let domElement = keyedElements[key];
          if (domElement) {
            // 3. 看当前位置的元素是不是期望的元素
            if (oldDOM.childNodes[i] && oldDOM.childNodes[i] !== domElement) {
              oldDOM.insertBefore(domElement, oldDOM.childNodes[i]);
            }
          } else {
            // 4. 新增元素
            mountElement(child, oldDOM, oldDOM.childNodes[i]);
          }
        }
      });
    }

    // 删除节点
    let oldChildNodes = oldDOM.childNodes;
    if (oldChildNodes.length > virtualDOM.children.length) {
      // 有节点需要被删除
      if (hasNokey) {
        // 通过索引方式去删除
        for (
          let i = oldChildNodes.length - 1;
          i > virtualDOM.children.length - 1;
          i--
        ) {
          unmountNode(oldChildNodes[i]);
        }
      } else {
        // 通过 key 属性去删除
        for(let i=0; i<oldChildNodes.length; i++) {
          let oldChild = oldChildNodes[i];
          let oldChildKey = oldChild._virtualDOM.props.key
          let found = false
          for(let n = 0; n < virtualDOM.children.length; n++) {
            if(oldChildKey === virtualDOM.children[n].props.key) {
              // 找到了
              found = true
              break
            }
          }
          if(!found) {
            // 节点需要被删除
            unmountNode(oldChild)
          }
        }
      }
    }
  }
}
